﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;
using System.Diagnostics;

namespace AutoUpdate
{
    /// <summary>
	/// This class represents a Zip archive.  You can ask for the contained
	/// entries, or get an uncompressed file for a file entry.  
	/// </summary>
    public class ZipFile
    {
        List<ZipEntry> zipEntries;		// The collection of entries
        private ZipReader thisReader;
        private ZipWriter thisWriter;

        private Stream baseStream;		// Stream to which the writer writes 
        // both header and data, the reader
        // reads this
        private string zipName;
        private FrmAutoUpdate frmAU = null;
        /// <summary>
        /// Created a new Zip file with the given name.
        /// </summary>
        /// <param name="method"> Gzip or deflate</param>
        /// <param name="name"> Zip name</param>

        List<String> listaExecute = null;
        List<String> listaScripturi = null;
        public System.Configuration.Configuration csSection = null;
        public ZipFile(FrmAutoUpdate _frm,string name, byte method, FileMode mode, List<String> _listaExecute, List<String> _listaScripturi, System.Configuration.Configuration _csSection)
        {
            csSection = _csSection;
            frmAU = _frm;
            listaExecute = _listaExecute;
            listaScripturi = _listaScripturi;
            try
            {
                zipName = name;

                baseStream = new FileStream(zipName, mode);
                thisWriter = new ZipWriter(baseStream);
                thisWriter.Method = method;

                //New File
                thisWriter.WriteSuperHeader(0, method);

                int index1 = zipName.IndexOf(ZipConstants.Dot);
                int index2 = zipName.LastIndexOf(ZipConstants.BackSlash);
                thisReader = new ZipReader(frmAU,baseStream, zipName.Substring(index2,index1 - index2), listaExecute, listaScripturi,csSection);

                zipEntries = thisReader.GetAllEntries();
                /*Form1.toolStripLabel1.Text =
                    String.Format(
                    System.Threading.Thread.CurrentThread.CurrentUICulture,
                    ZipConstants.NewMessage, name);*/
            }
            catch (System.IO.IOException ex)
            {
                Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} ZipFile() exceptions:" + ex.Message);
                Trace.Flush();
                ZipConstants.ShowError(ZipConstants.IOError);

            }
        }

        /// <summary>
        /// Opens a Zip file with the given name.
        /// </summary>
        /// <param name="name"> Zip name</param>
        public ZipFile(FrmAutoUpdate _frm, string name, List<String> _listaExecute, List<String> _listaScripturi, System.Configuration.Configuration _csSection)
        {
            csSection = _csSection;
            frmAU = _frm;
            listaExecute = _listaExecute;
            listaScripturi = _listaScripturi;
            try
            {
                zipName = name;
                baseStream = new FileStream(zipName, FileMode.Open);
                thisWriter = new ZipWriter(baseStream);

                int index1 = zipName.LastIndexOf(ZipConstants.Dot);
                int index2 = zipName.LastIndexOf(ZipConstants.BackSlash);

                Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} ZipFile() Create thisReader(zipName=" + zipName + ",");
                Trace.Flush();
                try
                {
                    thisReader = new ZipReader(frmAU, baseStream, zipName.Substring(index2, index1 - index2), listaExecute, listaScripturi, csSection);
                }
                catch(Exception ex)
                {
                    Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} thisReader = new ZipReader exception: " + ex.Message);
                    Trace.Flush();
                    return;
                }

                Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} ZipFile() Get zipEntries= thisReader.GetAllEntries()");
                Trace.Flush();
                zipEntries = thisReader.GetAllEntries();

                thisWriter.Method = thisReader.Method;


                /*if (CompressionForm.statusMessage != String.Empty)
                    CompressionForm.statusMessage =
                    String.Format(
                    System.Threading.Thread.CurrentThread.CurrentUICulture,
                    ZipConstants.OpenMessage, name);*/
            }
            catch (IOException)
            {
                Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} ZipFile() exceptions: Error opening the file" );
                Trace.Flush();
                ZipConstants.ShowError("Error opening the file");
            }
            catch (ArgumentOutOfRangeException)
            {
                Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} ZipFile() exceptions: ZipConstants.CorruptedError");
                Trace.Flush();
                ZipConstants.ShowError(ZipConstants.CorruptedError);
            }
        }


        /// <summary>
        /// Gets offset to which the jump should be made by summing up 
        /// all the individual lengths.
        /// </summary>
        /// <returns>
        /// the offset from SeekOrigin.Begin
        /// </returns>
        private long GetOffset(int index)
        {
            if (index > zipEntries.Count)
                return -1;
            int jump = ZipConstants.SuperHeaderSize;
            int i;
            for (i = 0; i < index - 1; ++i)
            {
                ZipEntry entry = zipEntries[i];
                jump += ZipConstants.FixedHeaderSize + entry.NameLength
                    + entry.CompressedSize;
            }
            return jump;
        }

        public void Add(string fileName)
        {
            System.Globalization.CultureInfo ci =
                System.Threading.Thread.CurrentThread.CurrentUICulture;
            if (fileName.ToLower(ci).Equals(zipName.ToLower(ci)))
            {
                ZipConstants.ShowError("Cannot add the current xip file");
                //CompressionForm.statusMessage = String.Empty;
                return;
            }
            ZipEntry entry = new ZipEntry(fileName);
            thisWriter.Add(entry);

            /*if (CompressionForm.statusMessage.Length != 0)
            {*/
            zipEntries.Add(entry);
            thisWriter.CloseHeaders((Int16)zipEntries.Count);
            //}
        }

        public void Extract(int index, string path)
        {

            if (index < 0 || index >= zipEntries.Count)
            {
                ZipConstants.ShowError("Argument out of range" +
                    "exception");
                return;
            }
            thisReader.Extract(zipEntries[index], GetOffset(index + 1),
                    path);
        }

        public Boolean ExtractAll(string path, ListView lV)
        {
            Boolean ret = false;
            if (thisReader == null)
            {
                Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} ExtractAll() exceptions: thisReader == null");
                Trace.Flush();
                return ret;
            }
            try
            {
                ret = thisReader.ExtractAll(zipEntries, path, lV);
            }
            catch (Exception ex)
            {
                Trace.WriteLine("[" + DateTime.Now.ToString() + "]{AutoUpdate} ExtractAll() exceptions:" + ex.Message);
                Trace.Flush();
            }
            return ret;
        }

        /// <summary>
        /// Closes the ZipFile.  This also closes all input streams given by
        /// this class.  After this is called, no further method should be
        /// called.
        /// </summary>
        public void Close()
        {
            if (baseStream != null)
                baseStream.Close();
        }

        /// <summary>
        /// Gets the entries of compressed files.
        /// </summary>
        /// <returns>
        /// Collection of ZipEntries
        /// </returns>
        public List<ZipEntry> Entries
        {
            get
            {
                return zipEntries;
            }
        }

        public byte CompressionMethod()
        {
            return thisWriter.Method;
        }

        public int CheckFileExists(string fileName)
        {
            System.Globalization.CultureInfo ci =
                        System.Threading.Thread.CurrentThread.CurrentUICulture;
            int i = -1;
            foreach (ZipEntry eachEntry in zipEntries)
            {
                ++i;
                if (eachEntry.Name.ToLower(ci).Equals(fileName.ToLower(ci)))
                {
                    return i;
                }
            }
            return -1;
        }

        /// <summary>
        /// Remove an entry from the archive
        /// </summary>
        /// <param name="index">
        /// The index of the entry that is to be removed
        /// </param>
        private void DeleteEntryFromFile(int index)
        {
            long jump = ZipConstants.SuperHeaderSize;
            for (int i = 0; i < index; ++i)
            {
                jump += ZipConstants.FixedHeaderSize +
                    zipEntries[i].NameLength +
                    zipEntries[i].CompressedSize;
            }
            ZipEntry entry = zipEntries[index];
            long fileJump = ZipConstants.FixedHeaderSize +
                    entry.NameLength +
                    entry.CompressedSize;
            baseStream.Seek(jump + fileJump, SeekOrigin.Begin);
            long length = baseStream.Length - fileJump - jump;
            byte[] b = new byte[length];
            baseStream.Read(b, 0, (int)length);
            baseStream.Seek(jump, SeekOrigin.Begin);
            baseStream.Write(b, 0, (int)length);
            baseStream.SetLength(baseStream.Length - fileJump);
            //CompressionForm.statusMessage = "Removed successfully";
        }

        /// <summary>
        /// Remove an entry from the archive
        /// </summary>
        /// <param name="index">
        /// The index of the entry that is to be removed
        /// </param>
        public void Remove(int index)
        {
            long jump = ZipConstants.SuperHeaderSize;
            for (int i = 0; i < index; ++i)
            {
                jump += ZipConstants.FixedHeaderSize +
                    zipEntries[i].NameLength +
                    zipEntries[i].CompressedSize;
            }
            thisWriter.Remove(jump, zipEntries[index]);
            zipEntries.RemoveAt(index);
            /*if (CompressionForm.statusMessage.Length != 0)
            {*/
            thisWriter.CloseHeaders((Int16)zipEntries.Count);
            //}
        }

    }
}
